﻿#include <iostream>
#include "picDeal.h"
#include "everyClass.h"
using namespace std;
long base_shape::m_nCols = 18000;
long base_shape::m_nRows = 30000;
long base_shape::m_SRows = 30000;
int base_shape::m_FileCount = 0;
FILE* base_shape::m_fp = nullptr;
byte** base_shape::m_PicA = nullptr;
byte** base_shape::m_PicB = nullptr;

int main()
{
	clock_t start, end;//定义clock_t变量
	start = clock();//开始时间
	srand(time(nullptr));
	//数组和指针的区别和联系
	/*
	* 数组：数组是用于储存多个相同类型数据的集合。
	* 指针：指针相当于一个变量，但是它和不同变量不一样，它存放的是其它变量在内存中的地址。
	* 1.赋值：同类型指针变量可以相互赋值，数组不行，只能一个一个元素的赋值或拷贝
	* 2.存储方式
	* 数组：数组在内存中是连续存放的，开辟一块连续的内存空间。数组是根据数组的下进行访问的，多维数组在内存中是按照一维数组存储的，只是在逻辑上是多维的
	* 数组的存储空间，不是在静态区就是在栈上。
	* 指针：由于指针本身就是一个变量，再加上它所存放的也是变量，所以指针的存储空间不能确定。
	* 堆和栈
	* 栈：是由编译器在需要时自动分配，不需要时自动清除的变量存储区。通常存放局部变量、函数参数等
	* 是由new分配的内存块，由程序员释放（编译器不管），一般一个new与一个delete对应，一个new[]
	*与一个delete[]对应。如果程序员没有释放掉，资源将由操作系统在程序结束后自动回收
	*求sizeof
	* 数组所占存储空间的内存：sizeof（数组名),数组的大小：sizeof（数组名）/sizeof（数据类型）
	* 在32位平台下，无论指针的类型是什么，sizeof（指针名）都是4，在64位平台下，无论指针的类型是什么，sizeof（指针名）都是8。
	* //指针
	（1）指向对象的指针：（()里面的值是初始化值）
		int *p=new int(0) ;    delete p;
	（2）指向数组的指针：(n表示数组的大小，值不必再编译时确定，可以在运行时确定)
		int *p=new int[n];    delete[] p;
	（3）指向类的指针：(若构造函数有参数，则new Class后面有参数，否则调用默认构造函数，delete调用析构函数)
		Class *p=new Class;  delete p;
	（4）指针的指针：（二级指针）
		int **pp=new (int*)[1];
		pp[0]=new int[6];
		delete[] pp[0];
	*指针数组和数组指针
	（1）指针数组：它实际上是一个数组，数组的每个元素存放的是一个指针类型的元素。 
		int* arr[8];
		优先级问题：[]的优先级比*高
		说明arr是一个数组，而int*是数组里面的内容
		这句话的意思就是：arr是一个含有8和int*的数组
	（2）数组指针：它实际上是一个指针，该指针指向一个数组
		int (*arr)[8];
		由于[]的优先级比*高，因此在写数组指针的时候必须将*arr用括号括起来
		arr先和*结合，说明p是一个指针变量
		这句话的意思就是：指针arr指向一个大小为8个整型的数组。
	*数组传参时，会退化为指针，所以我们先来看看什么是退化！
（1）退化的意义：C语言只会以值拷贝的方式传递参数，参数传递时，如果只拷贝整个数组，效率会大大降低，并且在参数位于栈上，太大的数组拷贝将会导致栈溢出。
（2）因此，C语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时，将数组名看做常量指针，传数组首元素的地址。
	*一维数组的传参
	一维数组传参退化，用指针进行接收，传的是数组首元素的地址
	void test(int *arr)
		{}
	传过去是指针数组的数组名，代表首元素地址，首元素是个指针向数组的指针，再取地址，就表示二级指针，用二级指针接收
	void test2(int **arr)
		{}
	int main()
		{
		int arr[10] = {0};
		int *arr2[20] = {0};//指针的数组
		test(arr);
		test2(arr2);指针数组的数组名是指针的指针
		}
	*指针：
	* 一级指针的传参
	（1）可以是一个整形指针
	（2）可以是整型变量地址
	（3）可以是一维整型数组数组名
	void print(int* p, int sz)
	{
		int i = 0;
		for (i = 0; i < sz; i++)
		{
			printf("%d\n", *(p + i));
		}
	}
	*二级指针传参
	当函数参数部分是二级指针时，可以接受什么参数例如：test（int**p）
	（1）二级指针变量
	（2）一级指针变量地址
	（3）一维指针数组的数组名
	*函数指针与指针函数
	定义:int (*p)(int, int);
	通过函数指针调用函数
	int maxValue (int a, int b) {
		return a > b ? a : b;
	}

	int (*p)(int, int) = NULL;  //定义一个与maxValue兼容的指针
	p = maxValue;
	p(20, 45);  //通过指针调用
	指针函数(返回值是指针)
	int *p(int a,int b); //注意这里的*与P之间是没有括号的，所以含义是函数p(int,int)会返回一个（int *）指针
	int *pfun(int* arr,int n);
	int main(){
		int array[]={0,1,2,3,4};
		int len=sizeof(array)/sizeof(array[0]);
		int* p;
		int i;
		//指针函数的调用
		p=pfun(array,len);
		for(i=0;i<len;i++){
			printf("array[%d]=%d\n",i,*(p+i));
		}
		return 0;
	}
	int *pfun(int* arr,int n){
		int* p=arr;
		return p;
	}
	函数指针:函数指针其本质是一个指针变量，该指针变量指向一个函数,函数指针的重要意义在于函数回调
	回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针（地址）作为参数传递给另一个函数，
	当这个指针被用为调用它所指向的函数时，我们就说这是回调函数
	如果要将数组中大于50的数打印在控制台
	void compareNumberFunction(int *numberArray, int count, int compareNumber)
	{
		for (int i = 0; i < count; i++)
		{
			if (*(numberArray + i) > compareNumber)
			{
				printf("%d\n", *(numberArray + i));
			}
		}
	}
	int main()
	{

		int numberArray[5] = {15, 34, 44, 56, 64};
		int compareNumber = 50;
		compareNumberFunction(numberArray, 5, compareNumber);

		return 0;
	}
	换一个需求,将一个整形数组中比50小的打印在控制台？
	这两个需求很多代码都是相同的，只要更改一下判断条件即可
	只需要将判断部分的条件分离出来就可以
	BOOL compareGreater(int number, int compareNumber) {
		return number > compareNumber;
	}
	BOOL compareLess(int number, int compareNumber) {
		return number < compareNumber;
	}
	将这个函数作为compareNumberFunction的一个参数进行传递
	void compareNumberFunction(int *numberArray, int count, int compareNumber, BOOL (*p)(int, int))
	{
		for (int i = 0; i < count; i++)
		{
			if (p(*(numberArray + i), compareNumber)) //通过函数指针调用比较函数
			{
				printf("%d\n", *(numberArray + i));
			}
		}
	}
	具体使用的场景
	int main() {
		int numberArray[5] = {15, 34, 44, 56, 64};
		int compareNumber = 50;
		// 大于被比较数字情况：
		compareNumberFunction(numberArray, 5, compareNumber, compareGreater);
		// 小于被比较数字情况：
		compareNumberFunction(numberArray, 5, compareNumber, compareLess);
		return 0;
	}
	int (*p)(int,int)   //有参数，有返回值的函数
	void (*p)(int,int)  //有参数，无返回值的函数
	void (*p)()         //无参数，无返回值的函数
	注意函数的返回值和参数类型要匹配哦！另外注意解引用运算符*上面的括号不能掉！
	借助于函数指针作为参数实现“动态排序”
	//定义一个结构体
	typedef struct student
	{
		char name[20];
		int age;
		float score;
	}Student;

	//比较两个学生的年龄
	BOOL compareByAge(Student stu1, Student stu2)
	 {
		return stu1.age > stu2.age ? YES : NO;
	}

	//比较两个学生的成绩
	BOOL compareByScore(Student stu1, Student stu2)
	{
		return stu1.score > stu2.score ? YES : NO;
	}

	void sortStudents(Student *array, int n, BOOL(*p)(Student, Student))
	{
		Student temp;
		int flag = 0;
		for (int i = 0; i < n - 1 && flag == 0; i++)
		{
			flag = 1;
			for (int j = 0; j < n - i - 1; j++)
			{
				if (p(array[j], array[j + 1]))
				{
					temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
					flag = 0;
				}
			}
		}
	}

	int main() {

		Student stu1 = {"小明", 19, 98};
		Student stu2 = {"小红", 20, 78};
		Student stu3 = {"小白", 21, 88};
		Student stuArray[3] = {stu1, stu2, stu3};
		sortStudents(stuArray, 3, compareByScore);

		return 0;
	}
	*/
	//C语言printf函数的用法，输出函数的功能是将程序运行的结果输出到屏幕上
	//printf是格式输出函数,最后一个关键字f即格式(format)的意思,功能是按照用户指定的格式,把指定的数据显示到显示器屏幕上
	//printf是一个标准库函数,调用的一般形式为:printf("格式控制字符串",输出表列)
	//printf("f=%f,c=%f\n",f,c);
	//格式字符串是用双引号括起来的字符串,包含三类信息
	/*
	* C语言printf函数的用法，输出函数的功能是将程序运行的结果输出到屏幕上
	*printf是格式输出函数,最后一个关键字f即格式(format)的意思,功能是按照用户指定的格式,把指定的数据显示到显示器屏幕上
	*printf是一个标准库函数,调用的一般形式为:printf("格式控制字符串",输出值参数表)
	*printf("f=%f,c=%f\n",f,c);
	*格式字符串是用双引号括起来的字符串,包含三类信息
	（1）格式字符:由“%”引导,如%d,%f等,作用是控制输出字符的格式
	（2）转义字符:格式控制字符串里的转义字符按照转义后的含义输出，如"/n"即输出回车
	（3）普通字符，需要保持原样输出的字符，如上面函数中双引号内的"f="和"c="部分
	*输出值参数是需要输出的数据项的列表，输出的数据项可以是常量、变量或表达式，输出值参数之间用逗号分隔，其类型要和格式字符相匹配
	* 如果没有输出参数时，格式控制字符串不再需要格式字符
	* %o %x %X如果向输出前导符要在格式字符前加#，如%#o %#x %#X
		int a = 888, b = -666;
		printf("%d\%d", a, b);//输出带符号的十进制整数，正数的符号不输出。
	*指定输出数据占5列，输出的数据在域内向右靠齐，加-就是向左靠齐
		int a = 888, b = -666;
		printf("%-5d\n%5d", a, b);
	*如果指定域宽<输出数据长度，会按照原样输出
		int a = 888, b = -666;
		printf("%2d\n%0d", a, b);
	*若要输出long（长整型）数据，则在格式字符d前面加字母l（代表long），即“%ld”
	* 输出一个实数（包括单精度、双精度、长双精度），以小数形式输出
	* 如果小数部分很长，又不指定输出长度，实数中的整数部分全部输出，小数部分输出6位
		double a = 10;
		printf("%f\n", a/3);
	*%.nf可以控制输出的小数位数
		printf("%.15f\n", a/3);
	*%m.f也可以控制小数，前面控制域宽，小数后面控制小数点保留的位数
		printf("%3.1f\n", a/3);
	*%c和%s 
		char ch = 'abc';
		printf("%c\n", ch);
		char ch[] = "abd";
		printf("%s", ch);
	* printf的返回值
	* printf的返回值就是输出的字符数量
		int A = 43;
		printf("%d\n", printf("%d", printf("%d", A)));
	*返回值是是输出的字符数量，包括数字，字母，标点符号，空格，换行符等
		printf("%d\n", printf("0,1,2,3\n"));
	*printf注意点
	* 格式控制字符串中有%引导的格式字符时，输出值参数表中的数量以及类型必须和格式字符一致
		int a = 123;
		double b = 58.8, c = 1.0;
		printf("a=%d,b=%d\n",a,b );
		printf("a=%d,c=%f\n", a);
	*格式控制字符串中没有%引导的格式字符时,直接输出字符串内容，转义字符按照转义后的实际意义输出
		printf("Hello\n,World");
	*/
	printf("Hello\n,World");
	return 0;
}